#include "Local_connection.h"

const int Local_connection::K_ERROR_NO_DATA_RECEIVED(2);
const int Local_connection::K_ERROR_SERVER_DISCONNECT(1);
const int Local_connection::K_SUCCESS(0);

const int Local_connection::K_BUFFER_SIZE(1024);


Local_connection::Local_connection(void) {}

Local_connection::~Local_connection(void) {
	WSACleanup();
}

bool Local_connection::create_connection(unsigned int port) {
	this->m_port = 0;

	WSACleanup();

	if (WSAStartup(MAKEWORD(2, 2), &m_wsa_data) != NO_ERROR) {
		WSACleanup();
		return false;
	}

	m_connection_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (m_connection_socket == INVALID_SOCKET) {
		WSACleanup();
		return false;
	}

	sockaddr_in address;

	address.sin_family = AF_INET;
	address.sin_addr.s_addr = inet_addr("127.0.0.1");
	address.sin_port = htons(port);

	if (connect(m_connection_socket, (SOCKADDR*) &address, sizeof(address)) == SOCKET_ERROR ) {
		WSACleanup();
		return false;
	}

	this->m_port = port;

	return true;
}

bool Local_connection::close_connection() {
	closesocket(m_connection_socket);

	return true;
}

bool Local_connection::send_message(std::string message, int &error_code) {
	send(m_connection_socket, std::string(message + "\n").c_str(), message.size() + 1, 0);

	if(WSAGetLastError() != 0) {
		error_code = 1;
		return false;
	}

	error_code = K_SUCCESS;
	return true;
}

std::string Local_connection::receive_message(bool block, int &error_code) {
	static char buffer[K_BUFFER_SIZE];

	if(block) {
		set_blocking();
	} else {
		set_non_blocking();
	}

	int received_bytes = recv(m_connection_socket, buffer, K_BUFFER_SIZE, 0);

	int n_error = WSAGetLastError();
	if(n_error != 0) {
		if(n_error == WSAEWOULDBLOCK) {
			error_code = get_code_error_no_data_received();
		} else {
			error_code = get_code_error_server_disconnect();
		}

		return "";
	}

	error_code = get_code_success();
	
	buffer[received_bytes] = '\0';
	return std::string(buffer);
}

void Local_connection::set_blocking() {
	u_long i_mode = 0;
	ioctlsocket(m_connection_socket, FIONBIO, &i_mode);
}

void Local_connection::set_non_blocking() {
	u_long i_mode = 1;
	ioctlsocket(m_connection_socket, FIONBIO, &i_mode);
}

int Local_connection::get_code_success() {
	return K_SUCCESS;
}

int Local_connection::get_code_error_server_disconnect() {
	return K_ERROR_SERVER_DISCONNECT;
}

int Local_connection::get_code_error_no_data_received() {
	return K_ERROR_NO_DATA_RECEIVED;
}

